﻿using BZ.Logger;
using HalconDotNet;
using NDK.Module.BLL;
using NDK.Module.Model;
using NDK.Motion.BLL;
using NDK.Motion.Monitor;
using NDK.Motion.StationLogic;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using VisionPlatform;

namespace NDK.Module.StationLogic
{
    [Monitor(Description = "定位工位")]
    public class LoadingProduct : StationLogic
    {
        #region 通用
        //记录当前步骤，用于步骤变化的比较
        private StationStep _curStep = StationStep.判断模式;
        //对外提供工位的步骤变化事件
        public override event PropertyChangedEventHandler PropertyChanged;
        //对外提供唯一实例
        public static LoadingProduct Instance = new LoadingProduct();
        //私有化的构造函数
        private LoadingProduct () : base()
        {
            this.Name = "上料定位拍照";
        }
        //步骤字段、属性
        private StationStep _step = StationStep.判断模式;
        [Monitor(Description = "当前步骤")]
        public StationStep Step
        {
            get
            {
                return _step;
            }
            set
            {
                if(_curStep != value)
                {
                    _step = value;
                    _curStep = value;

                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value.ToString()));
                }
            }
        }
        #endregion


        double X1 = 0, X2 = 0, Y1 = 0, Y2 = 0, R1 = 0, R2 = 0;

        /// <summary>
        /// 工站初始化
        /// </summary>
        public override void Init ()
        {
            base.Init();
            Step = StationStep.判断模式;
            logBaseInfo = "LoadingProduct1";

            CaptureImage1Count = 0;
            eng = new VisionManager.Engine("定位计算");
            CCD = Common.MVCameraList.getObject("LoadingLocationCCD1");
        }

        /// <summary>
        /// 工站动作流程
        /// </summary>
        /// <param name="mode"></param>
        public override void ActionProcess ()
        {
            try
            {
                switch(this.Step)
                {
                    case StationStep.判断模式:
                        if(Common.是否联机上料PLC)
                        {
                            Step = StationStep.流程开始;
                        }
                        break;

                    case StationStep.流程开始:
                        logCtStr = string.Empty;
                        swStepTime.Restart();
                        swStationCT.Restart();
                        logCtStr += $"{logBaseInfo},工位开始,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                        Step = StationStep.等待拍照;
                        break;

                    case StationStep.等待拍照:
                        if(Common.dic_plcComm_Bool["stPLC_PC.bCCD_Req[0]"])
                        {
                            CaptureImage1Count = 0;
                            Common.AppendUiLog.Log($"上料定位工位已收到拍照请求信号", LogType.Info);
                            Step = StationStep.触发拍照;
                        }
                        break;

                    case StationStep.触发拍照:
                        Machine.imageLights_产品1定位拍照.Open();
                        CCD.Snap();
                        hImage_Cam = CCD.Image();
                        if(hImage_Cam == null)
                        {
                            CaptureImage1Count++;
                            if(CaptureImage1Count < 3)
                            {
                                Thread.Sleep(1000);
                                break;
                            }
                            else
                            {
                                if(AlarmPause("采图异常", "Tray盘上料定位相机连续三次采集异常：", "请检查相机是否掉线及相机参数是否存在异常", " 再次拍照", "忽略继续") == DialogResult.OK)
                                {
                                    CaptureImage1Count = 0;
                                    PublicMethod.ReconnectCam(ref CCD, "LoadingLocationCCD1");
                                    break;
                                }
                            }
                        }
                        Machine.imageLights_产品1定位拍照.Close();
                        Step = StationStep.算法计算;
                        break;

                    case StationStep.算法计算:

                        if(StationManager.MachineProductionMode == RunningModeEnum.ProductionMode || StationManager.MachineProductionMode == RunningModeEnum.GRRMode)
                        {
                            List<DataItem> listDataItem = new List<DataItem>();
                            if(!LoadingCamVisionResult("定位计算", "Robot1", "Robot2", "Image", hImage_Cam, ref listDataItem, 1))
                            {
                                if(AlarmPause("算法异常", $"上料定位算法异常，请检查", "上料定位算法异常，请检查", "重新计算", "忽略报警，继续运行") == DialogResult.OK)
                                {
                                    break;
                                }
                            }
                            if(listDataItem != null)
                            {
                                if(listDataItem.Count != 0)
                                {
                                    try
                                    {
                                        X1 = Math.Round(listDataItem[0].Value, 2) + Convert.ToDouble(Common.偏移量X);
                                        Y1 = Math.Round(listDataItem[1].Value, 2) + Convert.ToDouble(Common.偏移量Y);
                                        R1 = Math.Round(listDataItem[2].Value, 2) + Convert.ToDouble(Common.偏移量Theta);
                                        X2 = Math.Round(listDataItem[3].Value, 2) + Convert.ToDouble(Common.偏移量X);
                                        Y2 = Math.Round(listDataItem[4].Value, 2) + Convert.ToDouble(Common.偏移量Y);
                                        R2 = Math.Round(listDataItem[5].Value, 2) + Convert.ToDouble(Common.偏移量Theta);
                                    }
                                    catch
                                    {
                                        //无需处理，异常后发送0给PLC，PLC处会报警重新触发
                                    }
                                }
                            }
                            if(hImage_Cam != null && Common.IsSaveImage)
                            {
                                string childPath = DateTime.Now.ToString("yyyy-MM-dd") + "\\" + Common.CurProType;
                                string LocalPath = Common.picSavePath + "\\" + childPath + "\\" + DateTime.Now.ToString("yyyy-MM-dd");
                                PublicMethod.SaveImageWithBarCode(hImage_Cam, LocalPath, "定位1" + "-" + DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"));
                            }
                        }

                        Step = StationStep.发送结果;
                        break;

                    case StationStep.发送结果:
                        isOK = PLCWriteMethod("Tray盘定位", ("stPC_PLC.wOffset_X1", null, (short)((X1 == 0 ? 0.01 : X1) * 100)),
                                                           ("stPC_PLC.wOffset_Y1", null, (short)((Y1 == 0 ? 0.01 : Y1) * 100)),
                                                           ("stPC_PLC.wOffset_R1", null, (short)((R1 == 0 ? 0.01 : R1) * 100)),
                                                           ("stPC_PLC.wOffset_X2", null, (short)((X2 == 0 ? 0.01 : X2) * 100)),
                                                           ("stPC_PLC.wOffset_Y2", null, (short)((Y2 == 0 ? 0.01 : Y2) * 100)),
                                                           ("stPC_PLC.wOffset_R2", null, (short)((R2 == 0 ? 0.01 : R2) * 100)));
                        if(!isOK)
                            break;
                        Step = StationStep.拍照完成;
                        break;

                    case StationStep.拍照完成:
                        if(PLCWriteMethod("Tray盘定位", ("stPC_PLC.bCCD_Comp[0]", true, null)))
                        {
                            Step = StationStep.等待结束;
                        }
                        break;

                    case StationStep.等待结束:
                        if(!Common.dic_plcComm_Bool["stPLC_PC.bCCD_Req[0]"])
                        {
                            Step = StationStep.流程结束;
                        }
                        break;

                    case StationStep.流程结束:
                        if(StationManager.MachineProductionMode == RunningModeEnum.ProductionMode)
                        {
                            logCtStr += $"{logBaseInfo},上料定位工位结束,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                            logCtStr += $"{logBaseInfo},上料定位工位结束,{swStationCT.ElapsedMilliseconds},{Environment.NewLine}";
                            PublicMethod.WriteLogToTxt(logCtStr, $"000StepCT_{DateTime.Now.ToString("yyyyMMdd")}", "上料定位工位");
                        }
                        Step = StationStep.判断模式;
                        break;
                }
            }
            catch(Exception ex)
            {
                UILog_Error($"[ LoadingProduct1 ActionProcess Thread ERROR] {ex.Message}");
            }
        }
        public override void EmptyActionProcess ()
        {
            ActionProcess();
        }

        public override void GRRActionProcess ()
        {
            ActionProcess();
        }

        /// <summary>
        /// 工位步骤定义
        /// </summary>
        public enum StationStep
        {
            判断模式,
            流程开始,
            等待拍照,
            触发拍照,
            算法计算,
            发送结果,
            拍照完成,
            等待结束,
            流程结束,
        }

        /// <summary>
        /// 获取相机算法结果
        /// </summary>
        /// <param name="FileName">算法流程文件名</param>
        /// <param name="outDataName">算法输出结果名称</param>
        /// <param name="listDataItems">输出的数据</param>
        /// <returns></returns>
        private bool LoadingCamVisionResult (string FileName, string outDataName, string outDataName1, string inputImageName, HImage InputImage, ref List<DataItem> listDataItems, int inputFixtureID = 0)
        {
            try
            {
                eng.SetInputNumber("PanNum", inputFixtureID);
                eng.SetInputImage(inputImageName, InputImage);
                eng.ActionFun();
                var strResult1 = eng.GetOutputString(outDataName);
                var strResult2 = eng.GetOutputString(outDataName1);
                if(strResult1 != "" && strResult2 != "")
                {
                    var dic1 = JsonConvert.DeserializeObject<Dictionary<string, double>>(strResult1);
                    var dic2 = JsonConvert.DeserializeObject<Dictionary<string, double>>(strResult2);
                    foreach(var item in dic1)
                    {
                        listDataItems.Add(new DataItem()
                        {
                            Name = item.Key,
                            Value = double.Parse(item.Value.ToString())
                        });
                    }
                    foreach(var item in dic2)
                    {
                        listDataItems.Add(new DataItem()
                        {
                            Name = item.Key,
                            Value = double.Parse(item.Value.ToString())
                        });
                    }
                }
            }
            catch(Exception ex)
            {
                Common.AppendUiLog.Log($"{FileName}算法流程异常" + ex.ToString(), LogType.Error);
                return false;
            }
            return true;
        }
    }
}
